package chapt05.spot;
// Spot.java
// OpenGL SuperBible
// Demonstrates OpenGL Spotlight
// Program by Richard S. Wright Jr.

import javax.media.opengl.GL2;
import javax.media.opengl.glu.GLU;

import com.jogamp.opengl.util.gl2.GLUT;

public class Spot
{
	static GLU glu = new GLU();
	static GLUT glut = new GLUT();
	
	// Rotation amounts
	static float xRot = 0.0f;
	static float yRot = 0.0f;
	
	// Light values and coordinates
	static float lightPos[] = {0.0f, 0.0f, 75.0f, 1.0f};
	static float specular[] = {1.0f, 1.0f, 1.0f, 1.0f};
	static float specref[] = {1.0f, 1.0f, 1.0f, 1.0f};
	static float ambientLight[] = {0.5f, 0.5f, 0.5f, 1.0f};
	static float spotDir[] = {0.0f, 0.0f, -1.0f};
	
	// Flags for effects
	static int MODE_FLAT = 1;
	static int MODE_SMOOTH = 2;
	static int MODE_VERYLOW = 3;
	static int MODE_MEDIUM = 4;
	static int MODE_VERYHIGH = 5;
	
	static int iShade = MODE_FLAT;
	static int iTess = MODE_VERYLOW;

	///////////////////////////////////////////////////////////////////////////////
	// Reset flags as appropriate in response to menu selections
	public static void processMenu(int value)
	{
	    switch(value)
        {
        	case 1:
        		iShade = MODE_FLAT;
        		break;

        	case 2:
        		iShade = MODE_SMOOTH;
        		break;

        	case 3:
        		iTess = MODE_VERYLOW;
        		break;

        	case 4:
        		iTess = MODE_MEDIUM;
        		break;

        	case 5:
        	default:
        		iTess = MODE_VERYHIGH;
            	break;
        }		
	}
	
	// This function does any needed initialization on the rendering
	// context. 
	protected static void setupRC(GL2 gl2, int width, int height)
	{
		gl2.glEnable(GL2.GL_DEPTH_TEST); // Hidden surface removal
		gl2.glFrontFace(GL2.GL_CCW);     // Counter clock-wise polygons face out
		gl2.glEnable(GL2.GL_CULL_FACE);  // Do not try to display the back sides
		
		// Enable lighting
		gl2.glEnable(GL2.GL_LIGHTING);
		
		// Setup and enable light 0
	    // Supply a slight ambient light so the objects can be seen
		gl2.glLightModelfv(GL2.GL_LIGHT_MODEL_AMBIENT, ambientLight, 0);
		
		// The light is composed of just a diffuse and specular component
		gl2.glLightfv(GL2.GL_LIGHT0, GL2.GL_DIFFUSE, ambientLight, 0);
		gl2.glLightfv(GL2.GL_LIGHT0, GL2.GL_SPECULAR, specular, 0);
		gl2.glLightfv(GL2.GL_LIGHT0, GL2.GL_POSITION, lightPos, 0);
		
		// Specific spot effects
		// Cut off angle is 60 degrees
		gl2.glLightf(GL2.GL_LIGHT0, GL2.GL_SPOT_CUTOFF, 50.0f);
		
		// Enable this light in particular
		gl2.glEnable(GL2.GL_LIGHT0);
		
		// Enable color tracking
		gl2.glEnable(GL2.GL_COLOR_MATERIAL);
		
		// Set Material properties to follow glColor values
		gl2.glColorMaterial(GL2.GL_FRONT, GL2.GL_AMBIENT_AND_DIFFUSE);
		
		// All materials hereafter have full specular reflectivity
		// with a high shine
		gl2.glMaterialfv(GL2.GL_FRONT, GL2.GL_SPECULAR, specref, 0);
		gl2.glMateriali(GL2.GL_FRONT, GL2.GL_SHININESS, 128);
		
		// Black background
		gl2.glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
	}
	
	// Called to draw scene
	protected static void renderScene(GL2 gl2, int w, int h)
	{	
		if(iShade == MODE_FLAT)
			gl2.glShadeModel(GL2.GL_FLAT);
		else // iShade = MODE_SMOOTH;
			gl2.glShadeModel(GL2.GL_SMOOTH);
		
		// Clear the window with current clearing color
		gl2.glClear(GL2.GL_COLOR_BUFFER_BIT | GL2.GL_DEPTH_BUFFER_BIT);
		
		// First place the light
		// Save the coordinate transformation
		gl2.glPushMatrix();
			// Rotate coordinate system
			gl2.glRotatef(yRot, 0.0f, 1.0f, 0.0f);
			gl2.glRotatef(xRot, 1.0f, 0.0f, 0.0f);
			
			// Specify new position and direction in rotated coords.
			gl2.glLightfv(GL2.GL_LIGHT0, GL2.GL_POSITION, lightPos, 0);
			gl2.glLightfv(GL2.GL_LIGHT0, GL2.GL_SPOT_DIRECTION, spotDir, 0);
			
			// Draw a red cone to enclose the light source
			gl2.glColor3ub((byte)255, (byte)0, (byte)0);
			
			// Translate origin to move the cone out to where the light
			// is positioned.
			gl2.glTranslatef(lightPos[0], lightPos[1], lightPos[2]);
			glut.glutSolidCone(4.0f, 6.0f, 15, 15);
			
			// Draw a smaller displaced sphere to denote the light bulb
			// Save the lighting state variable
			gl2.glPushAttrib(GL2.GL_LIGHTING_BIT);
			
				// Turn off lighting and specify a bright yellow sphere
				gl2.glDisable(GL2.GL_LIGHTING);
				gl2.glColor3ub((byte)255, (byte)255, (byte)0);
				glut.glutSolidSphere(3.0f, 15, 15);
				
			// Restore lighting state variables
			gl2.glPopAttrib();
			
		// Restore coordinate transformations
		gl2.glPopMatrix();
		
		// Set material color and draw a sphere in the middle
		gl2.glColor3ub((byte)0, (byte)0, (byte)255);
		
		if(iTess == MODE_VERYLOW)
			glut.glutSolidSphere(30.0f, 7, 7);
		else
			if(iTess == MODE_MEDIUM)
				glut.glutSolidSphere(30.0f, 15, 15);
			else // iTess = MODE_MEDIUM;
				glut.glutSolidSphere(30.0f, 50, 50);
		
		// Display the results
		gl2.glFlush();
	}
	
	public static void changeSize(GL2 gl2, int w, int h)
	{
		float fAspect;
		
		// Prevent a divide by zero
		if(h == 0)
			h = 1;
		
		// Set Viewport to window dimensions
		gl2.glViewport(0, 0, w, h);
		
		// Reset coordinate system
		gl2.glMatrixMode(GL2.GL_PROJECTION);
		gl2.glLoadIdentity();
		
		// Establish a viewing volume
		fAspect = (float)w / (float)h;
		glu.gluPerspective(35.0f, fAspect, 1.0f, 500.0f);
		
		gl2.glMatrixMode(GL2.GL_MODELVIEW);
		gl2.glLoadIdentity();
		gl2.glTranslatef(0.0f, 0.0f, -250.0f);		
	}
}